package fr.umlv.galcon.ship;

import java.awt.geom.Point2D;
import java.util.TimerTask;

import fr.umlv.galcon.game.GalconManager;
import fr.umlv.galcon.item.ItemListSingleton;
import fr.umlv.galcon.planet.Planet;

/**
 * This class is in charge of sending Ships between two Planets.
 */
public class SendShip extends TimerTask {
    private final Planet origin;
    private Planet destination;
    private final Squadron squadron;
    private int toSend;
    private final ShipProperties shipProperties;
    private final int originOwnerId;

    private Point2D originPoint;
    private Point2D currentPosition;

    /**
     * Constructor
     * 
     * @param origin
     *            Planet which send the ships.
     * @param destination
     *            Planet to reach.
     * @param toSend
     *            Quantity of ships to send.
     */
    public SendShip(Planet origin, Planet destination, int toSend) {
	this.origin = origin;
	this.destination = destination;
	this.toSend = toSend;
	this.squadron = new Squadron(origin, destination, origin.getOwner());
	this.shipProperties = origin.getShipProperties();
	this.originOwnerId = origin.getOwner().getId();
	this.originPoint = origin.getCenter();
	this.currentPosition = originPoint;
    }

    /**
     * Function which calculate the angle for the ship
     * 
     * @param sourcePoint
     *            The first point.
     * @param destinationPoint
     *            The second point.
     * @return The requested angle.
     */
    public static double getAngle(Point2D sourcePoint, Point2D destinationPoint) {
	double x1 = sourcePoint.getX();
	double y1 = sourcePoint.getY();
	double x2 = destinationPoint.getX();
	double y2 = destinationPoint.getY();

	double x3 = x1, y3 = y1;
	// Angle P3P1 with the horizontal
	double theta1 = Math.atan2(y1 - y3, x1 - x3);
	// Angle P3P2 with the horizontal
	double theta2 = Math.atan2(y2 - y3, x2 - x3);
	// Angle between the two points
	return theta2 - theta1;
    }

    /**
     * Function which change the destination planet
     * 
     * @param destination
     */
    public void changeDirection(Planet destination) {
	this.destination = destination;
	this.originPoint = currentPosition;
    }

    /**
     * Add the ships to a squadron and send it to its destination.
     */
    private void send() {
	Point2D destination = this.destination.getCenter();

	// Check if the planet has and is able to send ships.
	if (this.toSend > 0 && this.origin.getStock().getRealStock() >= 0) {

	    double x = this.originPoint.getX();
	    double y = this.originPoint.getY();
	    double xx, yy;
	    double radius = this.origin.getSize() / 1.6;
	    double angle = getAngle(this.origin.getCenter(), destination);

	    // Size of the Ships
	    int sizeShip = 12;

	    int cp = 0;
	    // Fewer the Planet is, higher the variation has to be
	    double variationBetweenShip = ((sizeShip * 100 / radius) / 100.0);
	    double endingAngle = angle + 1.6;

	    while (angle < endingAngle && this.toSend > 0) {
		// Increments or decrement the angle
		if (cp % 2 == 0) {
		    angle -= cp * variationBetweenShip;
		} else {
		    angle += cp * variationBetweenShip;
		}
		cp++;

		// New position of the Ship
		xx = x + radius * Math.cos(angle);
		yy = y + radius * Math.sin(angle);
		currentPosition = new Point2D.Double(xx, yy);

		// Put the Ships at the starting point
		ShipAbstract s = this.origin.getShipProperties().createShip((int) xx, (int) yy, sizeShip, this.squadron);

		// Order the ship to calculate his trajectory
		s.getShipMovement().setTrajectory();

		// Add the Ship to the list of item
		// System.err.println(s);
		ItemListSingleton.getInstance().addShip(s);

		// Add the ship to this squadron
		this.squadron.addShip(s);

		// Reduce the quantity of Ships available on the origin Planet
		this.origin.getStock().reduceStock(1);

		// Reduce the quantity of Ship to send
		this.toSend--;
	    }
	}
    }

    @Override
    public void run() {
	final int toSend = this.toSend;
	final ShipProperties shipProperties = this.shipProperties;
	final Planet origin = this.origin;
	final Squadron squad = this.squadron;
	final int originId = originOwnerId;

	if (toSend == 0 || originId != squad.getOriginPlanet().getOwner().getId() || shipProperties != origin.getShipProperties()
		|| GalconManager.getEndGame() || GalconManager.isOver()) {
	    cancel();

	}
	send();

    }
}
